package neuronalenetzeelearning.model;

// <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
import java.text.DecimalFormat;
import java.util.HashMap;

// #[regen=yes,id=DCE.40047059-820E-3F6D-A445-FA594A53CF54]
// </editor-fold> 
public class Matrix {

    private double[][] values;
    private final Graph graph;

    // <editor-fold defaultstate="collapsed" desc=" UML Marker "> 
    // #[regen=yes,id=DCE.F4343706-56C4-58CF-E0AE-F6CA9CA24349]
    // </editor-fold>
    /**
     * Die berechnete Gewichts-Matrix wird hier generiert/angezeigt.
     * Bekommt Info von edges
     * Zweidimensionales Array (Dim hängt von der Länge des edges-Vektors ab)
     *
     */
    private Matrix() {
        this(new Graph());
    }

    public Matrix(double[][] values) {
        this.values = values;
        //TODO calculate graph from matrix values
        this.graph = new Graph();
    }

    /**
     * zum Eintragen von Werten: zeilenweise durchgehen
     * Größe: n x n -Matrix mit n= nodes.size
     * Besetzung: Kantengewicht, falls vorhanden, sonst Null
     * Spalte:von Zeile:nach
     * @param graph Kantengewichte vom erzeugten Graphen
     * braucht: Vektor den Kanten und ihren Gewichten
     */
    public Matrix(Graph graph) {
        this.graph = graph;
    }

    public Matrix getSquareMatrix() {
        int n = graph.getNodes().size();
        double matrix[][] = new double[n][n];
        HashMap<Node, Integer> nodeToIndexMapping = graph.getMappingNodeToIndex();
        for (int i = 0; i < graph.getEdges().size(); i++) {//gehe alle kanten durch
            Edge edge = graph.getEdges().get(i);//kriege kante i
            Node nodeVon = edge.getFrom();//kriege den ursprungsknoten
            Node nodeZu = edge.getTo();//kriege den zielknoten
            int nodeVonIndex = nodeToIndexMapping.get(nodeVon);//nr des von-knotens
            int nodeZuIndex = nodeToIndexMapping.get(nodeZu);//nr des zu-knotens
            matrix[nodeVonIndex][nodeZuIndex] = edge.getWeight();//einrtag an die ensprechende stelle
        }
        this.values = matrix;
        return this;
    }

    public Matrix getTransitionMatrix() {
        int n = graph.getLayer1Nodes().size();//Zeilen VON
        int m =graph.getLayer2Nodes().size();//Spalten ZU
        double matrix[][] = new double[n][m];
        HashMap<Node, Integer> nodeToIndexMapping = graph.getMappingNodeToIndex();
        for (int i = 0; i < graph.getEdges().size(); i++) {//gehe alle kanten durch
              Edge edge = graph.getEdges().get(i);//kriege kante i
            Node nodeVon = edge.getFrom();//kriege den ursprungsknoten, es ex. n
            Node nodeZu = edge.getTo();//kriege den zielknoten, es ex m
            int nodeVonIndex = nodeToIndexMapping.get(nodeVon);//nr des von-knotens
            int nodeZuIndex = nodeToIndexMapping.get(nodeZu);//nr des zu-knotens
            matrix[nodeVonIndex][nodeZuIndex-n] = edge.getWeight();//einrtag an die ensprechende stelle
        }
        this.values = matrix;
        return this;
    }

    /**
     * generiert die Matrixausgabe
     * @return Matrixausgabe
     */
    @Override
    public String toString() {
        StringBuffer str = new StringBuffer();
        DecimalFormat df = new DecimalFormat( "0.##" );
        //Anz. der Knoten in der 2. Schicht
        for (int i = 0; i < values.length; i++) {
            //Anz. der Knoten in der 1. Schicht
            for (int j = 0; j < values[i].length; j++) {
                str.append(df.format(values[i][j]) + "\t"); //soll spaltenweise schreiben --> i=Spalte; j=Zeile
            }
            str.append("\n");
        }

        return str.toString();

    }

    /**
     * author: Henning Ainödhofer
     * Diese Methode brauche ich wahrscheinlich nur vorrübergehend, um die Matrix in der GUI anzuzeigen.
     * Da dies im ferigen Projekt über andere Stellen läuft, müssten die Methoden angepasst werden.
     * @return Matrixwerte
     */
    public double[][] getValues() {
        return this.values;
    }
}

